//@author A0081229H
package storage;

import java.util.ArrayList;

public class TimeRange implements Comparable<TimeRange>, Clonable<TimeRange>, Observer, Observable, Twinnable{

	private static final String SETSTARTTIME = "setStartTime";
	private static final String SETENDTIME = "setEndTime";

	private Time startTime, endTime;

	private ArrayList<Observer> observerList;
	Twinnable twin = null;


	// Constructors

	public TimeRange(Time pStartTime, Time pEndTime) throws Exception {
		try{
			StorageLogger.log(this.getClass().getCanonicalName());
		} catch (Exception e) {

		}
		assert ((pStartTime == null) || (pEndTime == null)): Helper.ERROR_NULL;
		startTime = pStartTime;
		startTime.addObs(this);
		endTime = pEndTime;
		endTime.addObs(this);
		observerList = new ArrayList<Observer>();

	}

	// Access Methods

	public Time getStartTime() {
		return startTime;
	}

	public Time getEndTime() {
		return endTime;
	}

	// Verification Methods

	public boolean isComplete() {
		if (!startTime.isEmpty() &&
				!endTime.isEmpty()) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isEmpty() {
		if (startTime.isEmpty() &&
				endTime.isEmpty()) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isDeadline() {
		if (startTime.isEmpty() &&
				!endTime.isEmpty()) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isInverted() {
		if (startTime.compareTo(endTime) == Helper.MORE) {
			return true;
		} else {
			return false;
		}
	}

	// Modification Methods

	public boolean setStartTime(Time pTime) {
		try{
			StorageLogger.log(this.getClass().getCanonicalName() +
					Helper.SPACE + SETSTARTTIME + Helper.SPACE +
					pTime.getClass().getCanonicalName());
		} catch (Exception e) {

		}
		if (pTime == null) {
			return false;
		}
		if (twin != null) {
			if (twin.isSame() &&
					endTime.compareTo(startTime) == Helper.LESS) {
				return false;
			}
		}
		startTime = pTime;
		notifyObs();
		return true;
	}

	public boolean setEndTime(Time pTime) {
		try{
			StorageLogger.log(this.getClass().getCanonicalName() +
					Helper.SPACE + SETENDTIME + Helper.SPACE +
					pTime.getClass().getCanonicalName());
		} catch (Exception e) {

		}
		if (pTime == null) {
			return false;
		}
		if (twin != null) {
			if (twin.isSame() &&
					endTime.compareTo(startTime) == Helper.LESS) {
				return false;
			}
		}
		endTime = pTime;
		notifyObs();
		return true;
	}

	// Interfaces

	@Override
	public int compareTo(TimeRange pTimeRange) {
		return Helper.compareSameStyle(getStartTime().compareTo(pTimeRange.getStartTime()),
				getEndTime().compareTo(pTimeRange.getEndTime()));
	}

	@Override
	public TimeRange cloneSelf() throws Exception {
		TimeRange cloneTimeRange;
		Time cloneStartTime = getStartTime().cloneSelf();
		Time cloneEndTime = getEndTime().cloneSelf();
		cloneTimeRange = new TimeRange(cloneStartTime, cloneEndTime);
		return cloneTimeRange;
	}

	@Override
	public void update() {
		notifyObs();		
	}

	@Override
	public void notifyObs() {
		for (Observer o : observerList) {
			o.update();
		}		
	}

	@Override
	public void addObs(Observer o) {
		observerList.add(o);

	}

	@Override
	public void addTwin(Twinnable t) {
		twin = t;

	}

	@Override
	public boolean isSame() {
		return (startTime.compareTo(endTime) == Helper.SAME);
	}


	@Override
	public boolean equals(Object obj) {
		if(obj instanceof TimeRange) {
			TimeRange timeRange = (TimeRange) obj;
			return this.startTime.equals(timeRange.startTime)
					&& this.endTime.equals(timeRange.endTime);
		}
		else {
			return false;
		}
	}

}
